
import java.io.*;
import java.util.Random;

public class Board
{
	Stone stone;
	Player player0;
	Player player1;
	static int countStone0;		// On Board stones
	static int countStone1;
	Stone [][] board;
	Random rand = new Random();
	BufferedReader verve = new BufferedReader(new InputStreamReader(System.in));
	

	// Board's constructor
	public Board() throws IOException
	{
		countStone0 = 0;
		countStone1 = 0;
		board = new Stone[7][7];
		printBoard();
		run();
	}

	// Method for generating random integers within a certain range
	public int Randomize()
	{
		return rand.nextInt(7);
	}

	// Method for removing stones
	public void removeStone(Player p) throws IOException
	{
		int x;
		int y;
		if(!p.getPlayerName().equals("DARWIN"))
			System.out.println("\n" + p.getPlayerName() + ", You have formed a mill, you will remove a stone from your opponent.");
		if(p.getPlayerName().equals("DARWIN"))
		{
			x = Randomize();
			y = Randomize();
		}
		else
		{
			System.out.print("Please enter X coordinate of Opponent's stone: ");
			x = Integer.parseInt(verve.readLine());
			System.out.print("Please enter Y coordinate of Opponent's stone: ");
			y = Integer.parseInt(verve.readLine());
		}
		try
		{
			int countMills0 = 0;
			int countMills1 = 0;
			for(int i = 0; i < 7; i++)
			{
				for(int j = 0; j < 7; j++)
				{
					if(checkVerticalMill(board[i][j]) || checkHorizontalMill(board[i][j]))
					{
						if(p.getPlayerNumber() == 0)
							countMills0++;
						else
							countMills1++;
					}
				}
			}
			if(countMills0 == countStone0 || countMills1 == countStone1)
			{
				if(board[x][y].getColor() != p.getPlayerNumber())
				{
					board[x][y] = null;
					if(p.getPlayerNumber() == 0)
						countStone0--;
					else
						countStone1--;
				}
			}
			else
			if(board[x][y].getColor() != p.getPlayerNumber())
			{
				if((checkVerticalMill(board[x][y]) == false) && (checkHorizontalMill(board[x][y]) == false) && (checkLegalPosition(x,y)))
				{
					board[x][y] = null;
					if(p.getPlayerNumber() == 0)
						countStone0--;
					else
						countStone1--;
				}
				else
				{
					if(!p.getPlayerName().equals("DARWIN"))
						System.out.println("You cannot remove a stone which is in a mill.");
					removeStone(p);
				}
			}
			else
			{
				if(!p.getPlayerName().equals("DARWIN"))
					System.out.println("You cannot remove your own Stone.");
				removeStone(p);
			}
		}
		catch(NullPointerException e)
		{
			removeStone(p);
		}
	}

	// Method for checking on empty position
	public boolean checkEmptyPosition(int row, int column)
	{
		if(board[row][column] == null)
			return true;
		else
			return false;
	}

	// Method for checking on a legal board position
	public boolean checkLegalPosition(int x, int y)
	{
		if((x == 0 || x == 6) && (y == 0 || y == 3 || y == 6))
				return true;
		else
			if((x == 1 || x == 5) && (y == 1 || y == 3 || y == 5))
				return true;
		else
			if((x == 2 || x == 4) && (y == 2 || y == 3 || y == 4)) 
				return true;
		else
			if((x == 3) && (y == 0 || y == 1 || y == 2 || y == 4 || y == 5 || y == 6))
				return true;
		else
			if((y == 3) && (x == 0 || x == 1 || x == 2 || x == 4 || x == 5 || x == 6))
				return true;
		else
			return false;
	}

	// Method for inserting stones on the board
	public void insertStone(Player p) throws IOException
	{
		try
		{
			int x;
			int y;
			if(p.getPlayerName().equals("DARWIN"))
			{
				x = Randomize();
				y = Randomize();
			}
			else
			{
				System.out.println((p.getPlayerName())+" Enter Row: ");
				x = Integer.parseInt(verve.readLine());
				System.out.println((p.getPlayerName())+" Enter Column: ");
				y = Integer.parseInt(verve.readLine());
			}
			
			if(checkEmptyPosition(x, y) == true && checkLegalPosition(x, y) == true)
			{
				board[x][y] = new Stone(x, y, p.getPlayerNumber());
				System.out.println("Player: " + board[x][y].getColor() + " The number of remaining stones is: " + board[x][y].getRemaining());
				
				if(p.getPlayerNumber() == 0)
					countStone0++;
				else
					countStone1++;
			}
			else
			{
				if(!p.getPlayerName().equals("DARWIN"))
					System.out.println("This position is not empty");
				insertStone(p);
			}
		
			// If a Mill is formed
			if(checkHorizontalMill(board[x][y]))
				removeStone(p);
			if(checkVerticalMill(board[x][y]))
				removeStone(p);
		}
		catch(NumberFormatException e)
		{
			System.out.println("The number you inserted is not recognized");
			insertStone(p);
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			if(!p.getPlayerName().equals("DARWIN"))
				System.out.println("This is not a valid place.");
			insertStone(p);
		}
	}

	// Method for moving stones from one place to another
	public boolean Move(Player p) throws IOException 
	{
		try
		{
			int x, y;
			int x1, y1;
			if(p.getPlayerName().equals("DARWIN"))
			{
				x = Randomize();
				y = Randomize();
				x1 = Randomize();
				y1 = Randomize();
			}
			else
			{
				System.out.print("Enter the X-Coordinate of the stone you want to move: ");
				x = Integer.parseInt(verve.readLine());
				System.out.print("Enter the Y-Coordinate of the stone you want to move: ");
				y = Integer.parseInt(verve.readLine());
				System.out.print("Enter the X-Coordinate of Destination: ");
				x1 = Integer.parseInt(verve.readLine());
				System.out.print("Enter the Y-Coordinate of Destination: ");
				y1 = Integer.parseInt(verve.readLine());
			}
/*			if(countStone0 == 3 || countStone1 == 3)
			{
				if((checkEmptyPosition(x1, y1) == true) && (checkLegalPosition(x1, y1) == true) && (board[x][y].getColor()==p.getPlayerNumber()))
				{
					board[x1][y1] = board[x][y];
					board[x][y] = null;
					board[x1][y1].setPosition(x1, y1);
				}
			}*/
			if((checkEmptyPosition(x1, y1) == true) && (checkLegalPosition(x1, y1) == true) && (checkPossibleMove(x, y, x1, y1) == true) && (board[x][y].getColor() == p.getPlayerNumber()))
			{
				board[x1][y1] = board[x][y];
				board[x][y] = null;
				board[x1][y1].setPosition(x1, y1);
			}
			else
			{
				if(!p.getPlayerName().equals("DARWIN"))
				System.out.println("Please enter correct coordinates");
				Move(p);
			}
		
			if(checkVerticalMill(board[x1][y1]) || checkHorizontalMill(board[x1][y1]))
				return true;
			else
				return false;		
		}
		catch(NullPointerException e)
		{
			Move(p);
			return false;
		}
	}

	// Method for checking ALL possible moves for a certain stone
	public boolean checkAllPossibleMoves(Stone s)
	{
		int x = s.getRow();
		int y = s.getColumn();
		int z = 0;

		if((x == 0 || x == 6) || (y == 0 || y == 6))
			z = 3;

		if((x == 1 || x == 5) || (y == 1 || y == 5))
			z = 2;

		if((x == 2 || x == 4) || (y == 2 || y == 4))
			z = 1;

		// Couldn't think of any other way .. screw it for now
		try
        {if(board[x][y + z] == null)      return true;}		// tries if there is an empty space near a stone then return true if caught an
        catch(ArrayIndexOutOfBoundsException e){}			// array out of bound exception just skip the check

        try
        {if(board[x + z][y] == null)      return true;}
        catch(ArrayIndexOutOfBoundsException e){}

        try
        {if(board[x][y - z] == null)      return true;}
        catch(ArrayIndexOutOfBoundsException e){}

        try
        {if(board[x - z][y] == null)      return true;}
        catch(ArrayIndexOutOfBoundsException e){}

        return false;
	}

	// Method for checking on a specific possible move
	public boolean checkPossibleMove(int x, int y, int x1, int y1)
	{
		int temp;
		int z = 0;

		if(x == 0 || x == 6 || y == 0 || y == 6)
			z = 3;
		if(x == 1 || x == 5 || y == 1 || y == 5)
			z = 2;
		if(x == 2 || x == 4 || y == 2 || y == 4)
			z = 1;
		if(x == 3)
		{
			try
			{
				temp = y + 1;
				if(board[x][temp] == null && (x1 == x && y1 == temp))
					return true;
			}
			catch(ArrayIndexOutOfBoundsException e){}
			
			try
			{
				temp = y - 1;
				if(board[x][temp] == null && (x1 == x && y1 == temp))
					return true;
			}
			catch(ArrayIndexOutOfBoundsException e){}
		}

		if(y == 3)
		{
			try
			{
				temp = x + 1;
				if(board[temp][y] == null && (x1 == temp && y1 == y))
					return true;
			}
			catch(ArrayIndexOutOfBoundsException e){}
			
			try
			{
				temp = x - 1;
				if(board[temp][y] == null && (x1 == temp && y1 == y))
					return true;
			}
			catch(ArrayIndexOutOfBoundsException e){}
		}

		try
		{
			temp = y + z;
			if(board[x][temp] == null && (x1 == x && y1 == temp))
				return true;
		}
		catch(ArrayIndexOutOfBoundsException e){}

		try
		{
			temp = x + z;
			if(board[temp][y] == null && (x1 == temp && y1 == temp))
				return true;
		}
		catch(ArrayIndexOutOfBoundsException e){}

		try
		{
			temp = y - z;
			if(board[x][temp] == null && (x1 == x && y1 == temp))
				return true;
		}
		catch(ArrayIndexOutOfBoundsException e){}

		try
		{
			temp = x - z;
			if(board[temp][y] == null  && (x1 == temp && y1 == y))
				return true;
		}
		catch(ArrayIndexOutOfBoundsException e){}

		return false;
	}

	// Method for checking on winner
	public int checkWinner()
	{
		if ((countStone0 + stone.firstPlayerStones) < 3)	// firstPlayerStones variable is added so that checkWinner() isn't applied
		{													// during the begining of the game when the player inserts his first stone
			return 1;
		}
		else
		{
			if((countStone1 + stone.secondPlayerStones) < 3)
			{
				return 0;
			}
		}

		int counter0 = 0;
		int counter1 = 0;
		try
		{
			for(int i = 0; i < 7; i++)
			{
				for(int j = 0; j < 7; j++)
				{
					if(board[i][j].getColor() == 0 && checkAllPossibleMoves(board[i][j]) == false)
						counter0++;
					else
						if(board[i][j].getColor() == 1 && checkAllPossibleMoves(board[i][j]) == false)
							counter1++;
					continue;
				}
			}
		}
		catch(NullPointerException e)
		{
		}

			if(countStone0 == counter0)
			{
				System.out.println(player1.getPlayerName()+ " is the WINNER");
				return 1;
			}
			else
				if(countStone1 == counter1)
				{
					System.out.println(player0.getPlayerName()+ " is the WINNER");
					return 0;
				}
				else
				{
					return -1;		// It's a draw so far
				}

		}

	// Method for checking on Horizontal Mill for a certain stone
	public boolean checkHorizontalMill(Stone s)
	{
		try
		{
			int x = s.getRow();
			int y = s.getColumn();
			int z = 0;
			int w = 0;
			if(x == 0 || x == 6)
			{
				w = 0; 
				z = 3;
			}
		else if(x == 1 || x == 5)
		{
			w = 1 ; 
			z = 2;
		}
		else if(x == 2 || x == 4)
		{
			w = 2 ; 
			z = 1;
		}

		// Row 3, Column 3
		if(x == 3 && y < 3)
		{
			if((board[3][0].getColor() == board[3][1].getColor()) && (board[3][0].getColor() == board[3][2].getColor()))
				{System.out.println("x == 3 , y < 3");return true;}
		}
		else if(x == 3 && y > 3)
		{
			if((board[3][4].getColor() == board[3][5].getColor()) && (board[3][4].getColor() == board[3][6].getColor()))
			{System.out.println("x == 3 , y > 3");return true;}
		}

		// 2 stones, check third
		if((board[x][w].getColor()) == (board[x][3].getColor()))
		{
			z = w + (2*z);
			if((board[x][z].getColor() == board[x][3].getColor()))
			{
				return true;
			}
			else
				return false;
		}
		else
			return false;
		}

		catch(NullPointerException e)
		{
			return false;
		}
	}

	// Method for checking on a Vertical Mill for a certain stone
	public boolean checkVerticalMill(Stone s)
	{
		try
		{
			int x = s.getRow();
			int y = s.getColumn();
			int w = 0;
			int z = 0;
			if(y == 0 || y == 6)
			{
				w = 0; 
				z = 3;
			}
			else if(y == 1 || y == 5)
			{
				w = 1; 
				z = 2;
			}
			else if(y == 2 || y == 4)
			{ 
				w = 2; 
				z = 1;
			}
			else if(y == 3 && x < 3)
			{
				if((board[0][3].getColor() == board[1][3].getColor()) && (board[0][3].getColor() == board[2][3].getColor()))
				{System.out.print("");return true;}
			}
			else if(y == 3 && x > 3)
			{
				if((board[4][3].getColor() == board[5][3].getColor()) && (board[4][3].getColor() == board[6][3].getColor()))
				{System.out.print("");return true;}
			}
			if((board[w][y].getColor() == board[3][y].getColor()))
			{
				z = w + (z*2);
				if(board[z][y].getColor() == board[3][y].getColor())
				{
					return true;
				}
				else return false;
			}
			else return false;
		}
		catch(NullPointerException e)
		{
			return false;
		}
	}

	// Method for printing the board
	public void printBoard()
	{
		System.out.println("\t0\t1\t2\t3\t4\t5\t6");
		for(int i = 0; i < 7; i++)
		{
			System.out.print(i);
			System.out.print("-\t");
			for(int j = 0; j < 7; j++)
			{
				if(checkLegalPosition(i, j)==true)
				{
					if(board[i][j] != null)
						System.out.print(board[i][j].getColor());
					else
						System.out.print("-");
				}
				System.out.print("\t");
			}
			System.out.println("");
		}	
	}

	// Run method
	public void run() throws IOException
	{ 
		System.out.println("Enter First Player Name: ");
		String firstPlayerName = verve.readLine();

		player0 = new Player(firstPlayerName, 0);
		System.out.println("Enter Second Player Name: ");
		player1 = new Player(verve.readLine(), 1);

		int i = 0;
		while(stone.firstPlayerStones != 0 || stone.secondPlayerStones != 0)
		{
				if((i % 2) == 0)
				{
					insertStone(player0);
					i++;
				}
				else
				{
					insertStone(player1);
					i++;
				}
				printBoard();
		}

		System.out.println("\nLet's Begin Moving Stones");
		System.out.println("--------------------------");
		printBoard();
		i = 0;
		while(checkWinner() == -1)
		{
			try
			{
				System.out.println("Player " + (i % 2) + " Move ");

				if(i%2 == 0)
				{
					if(Move(player0))
						removeStone(player0);
				}
				else
				{
					if(Move(player1))
						removeStone(player1);
				}
				printBoard();
				i++;
			}
			catch(NumberFormatException e)
			{
				System.out.println("The number you inserted is not recognized");
				continue;
			}
			catch(ArrayIndexOutOfBoundsException e)
			{
				System.out.println("This is not a valid place.");
				continue;
			}
		}
	
	}
}
